/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package carstoredb.models;

import carstoredb.models.exceptions.NonexistentEntityException;
import java.io.Serializable;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

/**
 *
 * @author wuhao
 */
public class UserJpaController implements Serializable {

	public UserJpaController(EntityManagerFactory emf) {
		this.emf = emf;
	}
	private EntityManagerFactory emf = null;

	public EntityManager getEntityManager() {
		return emf.createEntityManager();
	}

	public void create(User user) {
		if (user.getOrderInfoCollection() == null) {
			user.setOrderInfoCollection(new ArrayList<OrderInfo>());
		}
		if (user.getUserInfoCollection() == null) {
			user.setUserInfoCollection(new ArrayList<UserInfo>());
		}
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			Collection<OrderInfo> attachedOrderInfoCollection = new ArrayList<OrderInfo>();
			for (OrderInfo orderInfoCollectionOrderInfoToAttach : user.getOrderInfoCollection()) {
				orderInfoCollectionOrderInfoToAttach = em.getReference(orderInfoCollectionOrderInfoToAttach.getClass(), orderInfoCollectionOrderInfoToAttach.getOrderId());
				attachedOrderInfoCollection.add(orderInfoCollectionOrderInfoToAttach);
			}
			user.setOrderInfoCollection(attachedOrderInfoCollection);
			Collection<UserInfo> attachedUserInfoCollection = new ArrayList<UserInfo>();
			for (UserInfo userInfoCollectionUserInfoToAttach : user.getUserInfoCollection()) {
				userInfoCollectionUserInfoToAttach = em.getReference(userInfoCollectionUserInfoToAttach.getClass(), userInfoCollectionUserInfoToAttach.getId());
				attachedUserInfoCollection.add(userInfoCollectionUserInfoToAttach);
			}
			user.setUserInfoCollection(attachedUserInfoCollection);
			em.persist(user);
			for (OrderInfo orderInfoCollectionOrderInfo : user.getOrderInfoCollection()) {
				User oldUserIdOfOrderInfoCollectionOrderInfo = orderInfoCollectionOrderInfo.getUserId();
				orderInfoCollectionOrderInfo.setUserId(user);
				orderInfoCollectionOrderInfo = em.merge(orderInfoCollectionOrderInfo);
				if (oldUserIdOfOrderInfoCollectionOrderInfo != null) {
					oldUserIdOfOrderInfoCollectionOrderInfo.getOrderInfoCollection().remove(orderInfoCollectionOrderInfo);
					oldUserIdOfOrderInfoCollectionOrderInfo = em.merge(oldUserIdOfOrderInfoCollectionOrderInfo);
				}
			}
			for (UserInfo userInfoCollectionUserInfo : user.getUserInfoCollection()) {
				User oldUserIdOfUserInfoCollectionUserInfo = userInfoCollectionUserInfo.getUserId();
				userInfoCollectionUserInfo.setUserId(user);
				userInfoCollectionUserInfo = em.merge(userInfoCollectionUserInfo);
				if (oldUserIdOfUserInfoCollectionUserInfo != null) {
					oldUserIdOfUserInfoCollectionUserInfo.getUserInfoCollection().remove(userInfoCollectionUserInfo);
					oldUserIdOfUserInfoCollectionUserInfo = em.merge(oldUserIdOfUserInfoCollectionUserInfo);
				}
			}
			em.getTransaction().commit();
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public void edit(User user) throws NonexistentEntityException, Exception {
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			User persistentUser = em.find(User.class, user.getUserId());
			Collection<OrderInfo> orderInfoCollectionOld = persistentUser.getOrderInfoCollection();
			Collection<OrderInfo> orderInfoCollectionNew = user.getOrderInfoCollection();
			Collection<UserInfo> userInfoCollectionOld = persistentUser.getUserInfoCollection();
			Collection<UserInfo> userInfoCollectionNew = user.getUserInfoCollection();
			Collection<OrderInfo> attachedOrderInfoCollectionNew = new ArrayList<OrderInfo>();
			for (OrderInfo orderInfoCollectionNewOrderInfoToAttach : orderInfoCollectionNew) {
				orderInfoCollectionNewOrderInfoToAttach = em.getReference(orderInfoCollectionNewOrderInfoToAttach.getClass(), orderInfoCollectionNewOrderInfoToAttach.getOrderId());
				attachedOrderInfoCollectionNew.add(orderInfoCollectionNewOrderInfoToAttach);
			}
			orderInfoCollectionNew = attachedOrderInfoCollectionNew;
			user.setOrderInfoCollection(orderInfoCollectionNew);
			Collection<UserInfo> attachedUserInfoCollectionNew = new ArrayList<UserInfo>();
			for (UserInfo userInfoCollectionNewUserInfoToAttach : userInfoCollectionNew) {
				userInfoCollectionNewUserInfoToAttach = em.getReference(userInfoCollectionNewUserInfoToAttach.getClass(), userInfoCollectionNewUserInfoToAttach.getId());
				attachedUserInfoCollectionNew.add(userInfoCollectionNewUserInfoToAttach);
			}
			userInfoCollectionNew = attachedUserInfoCollectionNew;
			user.setUserInfoCollection(userInfoCollectionNew);
			user = em.merge(user);
			for (OrderInfo orderInfoCollectionOldOrderInfo : orderInfoCollectionOld) {
				if (!orderInfoCollectionNew.contains(orderInfoCollectionOldOrderInfo)) {
					orderInfoCollectionOldOrderInfo.setUserId(null);
					orderInfoCollectionOldOrderInfo = em.merge(orderInfoCollectionOldOrderInfo);
				}
			}
			for (OrderInfo orderInfoCollectionNewOrderInfo : orderInfoCollectionNew) {
				if (!orderInfoCollectionOld.contains(orderInfoCollectionNewOrderInfo)) {
					User oldUserIdOfOrderInfoCollectionNewOrderInfo = orderInfoCollectionNewOrderInfo.getUserId();
					orderInfoCollectionNewOrderInfo.setUserId(user);
					orderInfoCollectionNewOrderInfo = em.merge(orderInfoCollectionNewOrderInfo);
					if (oldUserIdOfOrderInfoCollectionNewOrderInfo != null && !oldUserIdOfOrderInfoCollectionNewOrderInfo.equals(user)) {
						oldUserIdOfOrderInfoCollectionNewOrderInfo.getOrderInfoCollection().remove(orderInfoCollectionNewOrderInfo);
						oldUserIdOfOrderInfoCollectionNewOrderInfo = em.merge(oldUserIdOfOrderInfoCollectionNewOrderInfo);
					}
				}
			}
			for (UserInfo userInfoCollectionOldUserInfo : userInfoCollectionOld) {
				if (!userInfoCollectionNew.contains(userInfoCollectionOldUserInfo)) {
					userInfoCollectionOldUserInfo.setUserId(null);
					userInfoCollectionOldUserInfo = em.merge(userInfoCollectionOldUserInfo);
				}
			}
			for (UserInfo userInfoCollectionNewUserInfo : userInfoCollectionNew) {
				if (!userInfoCollectionOld.contains(userInfoCollectionNewUserInfo)) {
					User oldUserIdOfUserInfoCollectionNewUserInfo = userInfoCollectionNewUserInfo.getUserId();
					userInfoCollectionNewUserInfo.setUserId(user);
					userInfoCollectionNewUserInfo = em.merge(userInfoCollectionNewUserInfo);
					if (oldUserIdOfUserInfoCollectionNewUserInfo != null && !oldUserIdOfUserInfoCollectionNewUserInfo.equals(user)) {
						oldUserIdOfUserInfoCollectionNewUserInfo.getUserInfoCollection().remove(userInfoCollectionNewUserInfo);
						oldUserIdOfUserInfoCollectionNewUserInfo = em.merge(oldUserIdOfUserInfoCollectionNewUserInfo);
					}
				}
			}
			em.getTransaction().commit();
		} catch (Exception ex) {
			String msg = ex.getLocalizedMessage();
			if (msg == null || msg.length() == 0) {
				Integer id = user.getUserId();
				if (findUser(id) == null) {
					throw new NonexistentEntityException("The user with id " + id + " no longer exists.");
				}
			}
			throw ex;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public void destroy(Integer id) throws NonexistentEntityException {
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			User user;
			try {
				user = em.getReference(User.class, id);
				user.getUserId();
			} catch (EntityNotFoundException enfe) {
				throw new NonexistentEntityException("The user with id " + id + " no longer exists.", enfe);
			}
			Collection<OrderInfo> orderInfoCollection = user.getOrderInfoCollection();
			for (OrderInfo orderInfoCollectionOrderInfo : orderInfoCollection) {
				orderInfoCollectionOrderInfo.setUserId(null);
				orderInfoCollectionOrderInfo = em.merge(orderInfoCollectionOrderInfo);
			}
			Collection<UserInfo> userInfoCollection = user.getUserInfoCollection();
			for (UserInfo userInfoCollectionUserInfo : userInfoCollection) {
				userInfoCollectionUserInfo.setUserId(null);
				userInfoCollectionUserInfo = em.merge(userInfoCollectionUserInfo);
			}
			em.remove(user);
			em.getTransaction().commit();
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public List<User> findUserEntities() {
		return findUserEntities(true, -1, -1);
	}

	public List<User> findUserEntities(int maxResults, int firstResult) {
		return findUserEntities(false, maxResults, firstResult);
	}

	private List<User> findUserEntities(boolean all, int maxResults, int firstResult) {
		EntityManager em = getEntityManager();
		try {
			CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
			cq.select(cq.from(User.class));
			Query q = em.createQuery(cq);
			if (!all) {
				q.setMaxResults(maxResults);
				q.setFirstResult(firstResult);
			}
			return q.getResultList();
		} finally {
			em.close();
		}
	}

	public User findUser(Integer id) {
		EntityManager em = getEntityManager();
		try {
			return em.find(User.class, id);
		} finally {
			em.close();
		}
	}

	public int getUserCount() {
		EntityManager em = getEntityManager();
		try {
			CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
			Root<User> rt = cq.from(User.class);
			cq.select(em.getCriteriaBuilder().count(rt));
			Query q = em.createQuery(cq);
			return ((Long) q.getSingleResult()).intValue();
		} finally {
			em.close();
		}
	}
	
}
